package mcommand;

import java.io.FileInputStream;
import java.util.ArrayList;

import javax.xml.stream.XMLInputFactory;
import javax.xml.stream.XMLStreamConstants;
import javax.xml.stream.XMLStreamReader;

import mcommand.City.TownState;

/**
 * An easy to use tool to read from XML files. Provides Highscore reading.
 *
 * @author Marcel, Christian, Klaus
 *
 */
public class ToolXMLReader {
    // defines the paths for the xml files
    private static String highscorePath = "highscore.xml";
    private static String gameStatePath = "gamestate.xml";
    private static String statisticsPath = "statistics.xml";
    
    private final int NUM_CITIES = 6;

    /**
     * Tries to read the XML file for the highscore.
     * 
     * @return returns all HighscoreUnits out of "highscore.xml"
     */
    public final ArrayList<HighscoreUnit> readHighscoreFromXML() {
        ArrayList<HighscoreUnit> units = new ArrayList<HighscoreUnit>();

        XMLInputFactory factory = XMLInputFactory.newInstance();
        XMLStreamReader document;

        if (Board.DEBUG) {
            System.out.println("XML Highscore (" + highscorePath
                    + ") wird gelesen.");
        }

        String playername = "";
        int score = 0;

        try {
            document = factory.createXMLStreamReader(new FileInputStream(
                    highscorePath));

            while (document.hasNext()) {
                switch (document.getEventType()) {
                case XMLStreamConstants.END_DOCUMENT:
                    document.close();
                    break;

                case XMLStreamConstants.START_ELEMENT:
                    if (document.getLocalName().equals("player")) {
                        for (int i = 0; i < document.getAttributeCount(); i++) {
                            String attributeName = document
                                    .getAttributeLocalName(i);

                            if (attributeName.equals("playername")) {
                                playername = String.valueOf(document
                                        .getAttributeValue(i));
                            } else if (attributeName.equals("score")) {
                                score = Integer.valueOf(document
                                        .getAttributeValue(i));
                            }
                        }
                    }

                    break;

                case XMLStreamConstants.END_ELEMENT:
                    if (document.getLocalName().equals("player")) {
                        units.add(new HighscoreUnit(playername, score));
                    }
                    break;

                default:
                    break;
                }

                document.next();
            }
        } catch (Exception e) {
            System.err.println("Die XML Datei (highscore) konnte nicht gelesen werden");
        }

        if (Board.DEBUG) {
            System.out.println("XML Highscore erfolgreich gelesen.");
            System.out.println("XML Highscore insgesamt: " + units.size());
        }

        return units;
    }

    /**
     * Checks if there is a saved game State.
     *
     * @return true or false
     */
    public final boolean checkGameStateXML() {
        XMLInputFactory factory = XMLInputFactory.newInstance();
        XMLStreamReader document;

        boolean checkPlayername = false;
        boolean checkScore = false;
        boolean checkLevel = false;
        int checkCities = 0;

        try {
            document = factory.createXMLStreamReader(new FileInputStream(
                    gameStatePath));

            while (document.hasNext()) {
                switch (document.getEventType()) {
                case XMLStreamConstants.END_DOCUMENT:
                    document.close();
                    break;

                case XMLStreamConstants.START_ELEMENT:
                    if (document.getLocalName().equals("gamestate")) {
                        for (int i = 0; i < document.getAttributeCount(); i++) {
                            String attributeName = document
                                    .getAttributeLocalName(i);

                            if (attributeName.equals("playername")) {
                                checkPlayername = true;
                            } else if (attributeName.equals("score")) {
                                checkScore = true;
                            } else if (attributeName.equals("level")) {
                                checkLevel = true;
                            } else if (attributeName.contains("city_alive")) {
                                checkCities++;
                            }
                        }
                    }

                    break;

                case XMLStreamConstants.END_ELEMENT:
                    break;

                default:
                    break;
                }

                document.next();
            }
        } catch (Exception e) {
            System.out
                    .println("XML GS - Datei nicht vorhanden / nicht lesbar.");
            e.printStackTrace();
            return false;
        }

        if (Board.DEBUG) {
            System.out.println("XML GS - Datei vorhanden.");
        }

        if (!checkPlayername || !checkScore || !checkLevel
                || (checkCities != NUM_CITIES)) {
            if (Board.DEBUG) {
                System.err.println("XML GS - Kein Spielstand vorhanden.");
            }

            return false;
        }

        return true;
    }

    /**
     * Reads the playername from the xml file.
     * 
     * @return playername or error
     */
    public final String readPlayernameFromXML() {
        XMLInputFactory factory = XMLInputFactory.newInstance();
        XMLStreamReader document;

        if (Board.DEBUG) {
            System.out.println("XML GS - playername (" + gameStatePath
                    + ") wird gelesen.");
        }

        try {
            document = factory.createXMLStreamReader(new FileInputStream(
                    gameStatePath));

            while (document.hasNext()) {
                switch (document.getEventType()) {
                case XMLStreamConstants.END_DOCUMENT:
                    document.close();
                    break;

                case XMLStreamConstants.START_ELEMENT:
                    if (document.getLocalName().equals("gamestate")) {
                        for (int i = 0; i < document.getAttributeCount(); i++) {
                            String attributeName = document
                                    .getAttributeLocalName(i);

                            if (attributeName.equals("playername")) {
                                return String.valueOf(document
                                        .getAttributeValue(i));
                            }
                        }
                    }

                    break;

                case XMLStreamConstants.END_ELEMENT:
                    break;

                default:
                    break;
                }

                document.next();
            }
        } catch (Exception e) {
            System.err.println("Die XML Datei (gamestate) konnte nicht gelesen werden");
        }

        if (Board.DEBUG) {
            System.out.println("XML GS - playername erfolgreich gelesen.");
        }

        System.err.println("XML GS - playername fehlerhaft.");
        return "Error";
    }

    /**
     * Reads the score out of the xml file.
     * 
     * @return score or -999
     */
    public final int readScoreFromXML() {
        XMLInputFactory factory = XMLInputFactory.newInstance();
        XMLStreamReader document;

        if (Board.DEBUG) {
            System.out.println("XML GS - score (" + gameStatePath
                    + ") wird gelesen.");
        }

        try {
            document = factory.createXMLStreamReader(new FileInputStream(
                    gameStatePath));

            while (document.hasNext()) {
                switch (document.getEventType()) {
                case XMLStreamConstants.END_DOCUMENT:
                    document.close();
                    break;

                case XMLStreamConstants.START_ELEMENT:
                    if (document.getLocalName().equals("gamestate")) {
                        for (int i = 0; i < document.getAttributeCount(); i++) {
                            String attributeName = document
                                    .getAttributeLocalName(i);

                            if (attributeName.equals("score")) {
                                return Integer.parseInt((document
                                        .getAttributeValue(i)));
                            }
                        }
                    }

                    break;

                case XMLStreamConstants.END_ELEMENT:
                    break;

                default:
                    break;
                }

                document.next();
            }
        } catch (Exception e) {
            System.err.println("Die XML Datei (gamestate) konnte nicht gelesen werden");
        }

        if (Board.DEBUG) {
            System.out.println("XML GS - score erfolgreich gelesen.");
        }

        System.err.println("XML GS - score fehlerhaft.");
        return -999;
    }

    /**
     * Reads the level out of the xml file.
     * 
     * @return level or 1 (for level 1)
     */
    public final int readLevelFromXML() {
        XMLInputFactory factory = XMLInputFactory.newInstance();
        XMLStreamReader document;

        if (Board.DEBUG) {
            System.out.println("XML GS - level (" + gameStatePath
                    + ") wird gelesen.");
        }

        try {
            document = factory.createXMLStreamReader(new FileInputStream(
                    gameStatePath));

            while (document.hasNext()) {
                switch (document.getEventType()) {
                case XMLStreamConstants.END_DOCUMENT:
                    document.close();
                    break;

                case XMLStreamConstants.START_ELEMENT:
                    if (document.getLocalName().equals("gamestate")) {
                        for (int i = 0; i < document.getAttributeCount(); i++) {
                            String attributeName = document
                                    .getAttributeLocalName(i);

                            if (attributeName.equals("level")) {
                                return Integer.parseInt((document
                                        .getAttributeValue(i)));
                            }
                        }
                    }

                    break;

                case XMLStreamConstants.END_ELEMENT:
                    break;

                default:
                    break;
                }

                document.next();
            }
        } catch (Exception e) {
            System.err.println("Die XML Datei (gamestate) konnte nicht gelesen werden");
        }

        if (Board.DEBUG) {
            System.out.println("XML GS - level erfolgreich gelesen.");
        }

        System.err.println("XML GS - level fehlerhaft.");
        return 1;
    }

    /**
     * Reads out of the xml file which cities are alive.
     * 
     * @return readCities
     */
    public final ArrayList<City> readCitiesFromXML() {
        ArrayList<City> readCities = new ArrayList<City>();
        City readCity = new City();

        XMLInputFactory factory = XMLInputFactory.newInstance();
        XMLStreamReader document;

        if (Board.DEBUG) {
            System.out.println("XML GS - cities (" + gameStatePath
                    + ") wird gelesen.");
        }

        try {
            document = factory.createXMLStreamReader(new FileInputStream(
                    gameStatePath));

            while (document.hasNext()) {
                switch (document.getEventType()) {
                case XMLStreamConstants.END_DOCUMENT:
                    document.close();
                    break;

                case XMLStreamConstants.START_ELEMENT:
                    if (document.getLocalName().equals("gamestate")) {
                        for (int i = 0; i < document.getAttributeCount(); i++) {
                            String attributeName = document
                                    .getAttributeLocalName(i);

                            if (attributeName.contains("city_alive")) {
                                readCity = new City();

                                if (document.getAttributeValue(i)
                                        .equals("true")) {
                                    readCity.setState(TownState.ALIVE);
                                } else {
                                    readCity.setState(TownState.DESTROYED);
                                }
                                
                                readCities.add(readCity);
                            }
                        }
                    }

                    break;

                case XMLStreamConstants.END_ELEMENT:
                    break;

                default:
                    break;
                }

                document.next();
            }
        } catch (Exception e) {
            System.err.println("Die XML Datei (gamestate) konnte nicht gelesen werden");
        }

        if (Board.DEBUG) {
            System.out.println("XML GS - cities erfolgreich gelesen. ("
                    + readCities.size() + ")");
        }

        return readCities;
    }
    
    /**
     * Reads the statistic out of the xml file.
     * 
     * @param statName statName in XML file.
     * 
     * @return statistic value or 0
     */
    public final int readStatistics(final String statName) {
        XMLInputFactory factory = XMLInputFactory.newInstance();
        XMLStreamReader document;

        if (Board.DEBUG) {
            System.out.println("XML Stats - "
                    + statName +  " (" + statisticsPath
                    + ") wird gelesen.");
        }

        try {
            document = factory.createXMLStreamReader(new FileInputStream(
                    statisticsPath));

            while (document.hasNext()) {
                switch (document.getEventType()) {
                case XMLStreamConstants.END_DOCUMENT:
                    document.close();
                    break;

                case XMLStreamConstants.START_ELEMENT:
                    if (document.getLocalName().equals("statistics")) {
                        for (int i = 0; i < document.getAttributeCount(); i++) {
                            String attributeName = document
                                    .getAttributeLocalName(i);

                            if (attributeName.equals(statName)) {
                                return Integer.parseInt(
                                        document.getAttributeValue(i));
                            }
                        }
                    }

                    break;

                case XMLStreamConstants.END_ELEMENT:
                    break;

                default:
                    break;
                }

                document.next();
            }
        } catch (Exception e) {
            System.err.println("Die XML Datei (statistics) konnte nicht gelesen werden");
        }

        if (Board.DEBUG) {
            System.out.println("XML Stats - "
                    + statName + " erfolgreich gelesen.");
        }

        System.err.println("XML Stats - "
                + statName + " wurde nicht gefunden.");
        return 0;
    }
}
